package com.llb666.shop.order.application;

import com.alibaba.fastjson.JSON;
import com.llb666.common.core.constant.AppConstants;
import com.llb666.common.core.enums.PayMethod;
import com.llb666.common.core.exception.AppException;
import com.llb666.common.core.utils.cookie.CookieUtils;
import com.llb666.common.core.web.error.CommonError;
import com.llb666.common.core.web.response.BaseResponse;
import com.llb666.common.redis.service.RedisService;
import com.llb666.shop.cart.domain.entity.ShopCartBo;
import com.llb666.shop.order.api.dto.SubmitOrderDto;
import com.llb666.shop.order.api.vo.MerchantOrdersVo;
import com.llb666.shop.order.api.vo.OrderVo;
import com.llb666.shop.order.domain.client.PaymentOrderClient;
import com.llb666.shop.order.domain.service.OrderService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 订单应用层.
 *
 * @author llb666
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class OrderApplication {

    /**
     * 分布式锁
     */
    private final RedissonClient redissonClient;
    private final RedisService redisService;
    private final OrderService orderService;
    private final PaymentOrderClient paymentOrderClient;

    /**
     * 用户下单
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public String create(SubmitOrderDto submitOrderDto,
                         HttpServletRequest request,
                         HttpServletResponse response) {
        String orderTokenKey = "ORDER_TOKEN_" + request.getSession().getId();
        String lockKey = "LOCK_KEY_" + request.getSession().getId();
        // 分布式锁，高并发
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(5, TimeUnit.SECONDS);
        try {
            String orderToken = redisService.getCacheObject(orderTokenKey);
            if (StringUtils.isBlank(orderToken)) {
                throw new RuntimeException("orderToken不存在");
            }
            if (!orderToken.equals(submitOrderDto.getToken())) {
                throw new RuntimeException("orderToken不正确");
            }
        } finally {
            try {
                lock.unlock();
                redisService.deleteObject(orderTokenKey);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 校验
        if (!submitOrderDto.getPayMethod().equals(PayMethod.ALIPAY.type)
                && !submitOrderDto.getPayMethod().equals(PayMethod.WEIXIN.type)) {
            throw new AppException(CommonError.RequestParamsInvalid, "支付方式不支持！");
        }
        String shopCartJson = redisService.getCacheObject(AppConstants.SHOP_MALL_CART + ":" + submitOrderDto.getUserId());
        if (StringUtils.isBlank(shopCartJson)) {
            throw new AppException(CommonError.RequestParamsInvalid, "购物车数据有误！");
        }
        List<ShopCartBo> shopCartList = JSON.parseArray(shopCartJson, ShopCartBo.class);
        /*
         * 1. 创建订单
         */
        OrderVo orderVO = orderService.create(shopCartList, SubmitOrderDto.Converter.INSTANCE.dto2bo(submitOrderDto));
        String orderId = orderVO.getOrderId();
        /*
         * 2.移除购物车已经结算的商品
         * 整合redis之后，完善购物车中的已结算商品清除，并且同步到前端的cookie
         * 参考京东，没有付款完成，只要提交订单清理了购物车，但是我的订单中有代付款项
         */
        shopCartList.removeAll(orderVO.getToBeRemovedShopCartList());
        redisService.setCacheObject(AppConstants.SHOP_MALL_CART + ":" + submitOrderDto.getUserId(), JSON.toJSONString(shopCartList));
        CookieUtils.setCookie(request, response, AppConstants.SHOP_MALL_CART, JSON.toJSONString(shopCartList), true);
        /*
         * 3.发起支付
         */
        MerchantOrdersVo merchantOrdersVO = orderVO.getMerchantOrdersVo();
        merchantOrdersVO.setReturnUrl(AppConstants.PAY_RETURN_URL);
        //单位 1分钱
        merchantOrdersVO.setAmount(1);
        // 远程付费服务接口调用
        BaseResponse baseResponse = paymentOrderClient.createPaymentOrder(merchantOrdersVO.covert());
        boolean isPayment = baseResponse.getStatus().equals(200);
        if (!isPayment) {
            throw new AppException(CommonError.OrderCreateError, "支付中心订单创建失败，请联系管理员！");
        }
        return orderId;
    }
}
